﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using MediaAutomatorLib.Configurations;
using MediaAutomatorLib.MediaFinder;
using MediaAutomatorLib.ExternalPrograms;
using MediaAutomatorLib.Helpers;
using System.Net;

namespace MediaAutomatorLib.MediaOrganizer
{
    public class MediaOrganizer
    {
        private static Logger _logger;

        private DirectoryNode _downloadsNode;
        private DirectoryNode _tempMoviesNode;
        private DirectoryNode _tempTvShowsNode;
        private DirectoryNode _moviesLibraryNode;
        private DirectoryNode _tvShowsLibraryNode;
        private MediaTypeFinder _finder;
        private TheRenamerProgram _theRenamerProgram;
        private XbmcProgram _xbmcProgram;
        private UTorrentProgram _uTorrentProgram;


        private string _moviesTempFolderPath;
        private string _tvShowsTempFolderPath;        


        public MediaOrganizer(Configuration configuration)
        {

            _moviesTempFolderPath = Path.Combine(configuration.Temporary, "Movies");
            _tvShowsTempFolderPath = Path.Combine(configuration.Temporary, "TvShows");

            _finder = new MediaTypeFinder(configuration);
            _logger = new Logger(configuration.LogsFolderPath); 
            _theRenamerProgram = new TheRenamerProgram(configuration.TheRenamerPath, configuration.MoviesLibrary, configuration.TvShowsLibrary, _moviesTempFolderPath, _tvShowsTempFolderPath);
            _xbmcProgram = new XbmcProgram(configuration.XbmcHostname, configuration.XbmcPort, configuration.XbmcUsername, configuration.XbmcPassword);
            _uTorrentProgram = new UTorrentProgram(configuration.UTorrentHostname, configuration.UTorrentPort, configuration.UTorrentUsername, configuration.UTorrentPassword);

            
            LoadDirectoriesNodes(configuration);
            
            _logger.Log(configuration);
        }

        private static void CheckConfiguration(IDirectoriesConfiguration configuration)
        {
            if (configuration == null)
                throw new MediaAutomatorException("You must provide valid configuration object");
            if (String.IsNullOrEmpty(configuration.Downloads) || !Directory.Exists(configuration.Downloads))
                throw new MediaAutomatorException(
                    "You must specify a valid downloads directory path in the configuration");
            if (String.IsNullOrEmpty(configuration.MoviesLibrary) || !Directory.Exists(configuration.MoviesLibrary))
                throw new MediaAutomatorException(
                    "You must specify a valid movies library directory path in the configuration");
            if (String.IsNullOrEmpty(configuration.TvShowsLibrary) || !Directory.Exists(configuration.TvShowsLibrary))
                throw new MediaAutomatorException(
                    "You must specify tv shows library directory path in the configuration");
        }

        private void LoadTemporaryDirectories()
        {

            if (!Directory.Exists(_moviesTempFolderPath))
                Directory.CreateDirectory(_moviesTempFolderPath);

            if (!Directory.Exists(_tvShowsTempFolderPath))
                Directory.CreateDirectory(_tvShowsTempFolderPath);

            _tempMoviesNode = new DirectoryNode() {Path = _moviesTempFolderPath};
            _tempTvShowsNode = new DirectoryNode() {Path = _tvShowsTempFolderPath};
        }

        private void DeleteTemporaryDirectories()
        {
            try
            {
                Directory.Delete(_tempMoviesNode.Path);
                Directory.Delete(_tempTvShowsNode.Path);
            }
            catch (Exception e)
            {
                _logger.Log("Error deleting temporary folders");
                _logger.Log(e.ToString());
            }
        }


        private void LoadDirectoriesNodes(IDirectoriesConfiguration configuration)
        {
            CheckConfiguration(configuration);
            _downloadsNode = new DirectoryNode() {Path = configuration.Downloads};
            _moviesLibraryNode = new DirectoryNode() {Path = configuration.MoviesLibrary};
            _tvShowsLibraryNode = new DirectoryNode() {Path = configuration.TvShowsLibrary};

            LoadTemporaryDirectories();
        }

        private void MoveNodes(DirectoryNode sourceNode, DirectoryNode targetNode, MediaType type)
        {
            List<DirectoryNode> nodes = _finder.FindMediaNodes(sourceNode, type);
            foreach (var node in nodes)
            {
                try
                {
                    if (IsDirectory(node.Path))
                        Directory.Move(node.Path, Path.Combine(targetNode.Path, Path.GetFileName(node.Path)));
                    else
                        File.Move(node.Path, Path.Combine(targetNode.Path, Path.GetFileName(node.Path)));
                    _logger.Log("Moved '{0}' to '{1}'", node.Path, targetNode.Path);
                }catch(Exception e)
                {
                    _logger.Log("Fail to move '{0}' to '{1}'", node.Path, targetNode.Path);
                    _logger.Log(e.ToString());
                }

            }
        }

        private bool IsDirectory(string path)
        {
            return Directory.Exists(path);
        }


        public void Organize(String torrentHash)
        {           
            _logger.Log("Remove torrent with HASH: {0}", torrentHash);
            _uTorrentProgram.RemoveTorrent(torrentHash);
            Organize();
        }

        public void Organize()
        {
            try
            {
                
                // 1. Move videos to temporary folders (TV Shows and Movies)
                _logger.Log(">>>>>> Scan tv shows");
                MoveNodes(_downloadsNode, _tempTvShowsNode, MediaType.TvShow);                
                _logger.LogBreak();

                _logger.Log(">>>>>> Scan movies");
                MoveNodes(_downloadsNode, _tempMoviesNode, MediaType.Movie);
                _logger.LogBreak();

                
                
                // 2. Execute renaming for TV Shows and Movies
                _logger.Log(">>>>>> Fetch and rename videos with therenamer program");
                _theRenamerProgram.FetchTvShows();
                _theRenamerProgram.FetchMovies();
                _logger.LogBreak();
                // 3. Move tv shows that stills remains in temp folders. This means therenamer does not recogize those videos
               _logger.Log("****** TV Shows not recognized");
                MoveNodes(_tempTvShowsNode, _downloadsNode, MediaType.TvShow);
                _logger.LogBreak();
                _logger.Log("****** Movies not recognized");
                MoveNodes(_tempMoviesNode, _downloadsNode, MediaType.Movie);
                _logger.LogBreak();

                // 4. Delete temporary folders
                _logger.Log(">>>>>> Delete temporary folders");
                DeleteTemporaryDirectories();
                _logger.LogBreak();

                // 5. Update XBMC Video Library
                _xbmcProgram.UpdateVideoLibrary();
                
                


            }
            catch (Exception e)
            {
                _logger.Log(e.ToString());
            }
            finally
            {
                _logger.Flush();
            }
        }


    }
}
